package com.zhengx.fragmentutil;


import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle;

/**
 * name：com.zhengx.fragmentutil
 * class: 控制fragment的启动显示隐藏等
 * author: zhengx
 * create_time: 19-7-25
 */
public class FragController {

    private FragmentManager fragmentManager;

    private int fragmentContainerResId;

    public FragController(FragmentManager fragmentManager) {
        this.fragmentManager = fragmentManager;
    }

    protected void setContainerId(int containerId) {
        this.fragmentContainerResId = containerId;
    }

    /**
     * 获取当前fragment
     */
    public Fragment getTopFragment() {
        return fragmentManager.getPrimaryNavigationFragment();
    }

    /**
     * 根据类名（含包名）查找fragment
     */
    public Fragment findFragment(Class<? extends Fragment> fragClass) {
        return findFragment(fragClass, null);
    }

    /**
     * 根据类名（含包名）+ 后缀 查找fragment
     */
    public Fragment findFragment(Class<? extends Fragment> fragClass, String customTagSuffix) {
        return this.fragmentManager.findFragmentByTag(fragClass.getName() + (customTagSuffix != null ? customTagSuffix : ""));
    }

    /**
     * 初始化单个fragment
     */
    public Fragment initSingleFragment(@NonNull Fragment fragment) {

        FragmentTransaction ft = this.fragmentManager.beginTransaction();
        if (!fragment.isAdded()) {
            ft.add(this.fragmentContainerResId, fragment, fragment.getClass().getName());
        }
        ft
                .show(fragment)
                .setMaxLifecycle(fragment, Lifecycle.State.RESUMED)
                .setPrimaryNavigationFragment(fragment)
                .commitAllowingStateLoss();
        this.fragmentManager.executePendingTransactions();
        return fragment;
    }

    /**
     * 初始化多个fragment
     */
    public Fragment[] initMultiFragments(@NonNull Fragment[] fragments) {
        return initMultiFragments(0, fragments, new String[fragments.length]);
    }

    /**
     * 初始化多个fragment
     */
    public Fragment[] initMultiFragments(@NonNull Fragment[] fragments, String[] tags) {
        return initMultiFragments(0, fragments, tags);
    }

    /**
     * 初始化多个fragment
     */
    public Fragment[] initMultiFragments(int showIndex, @NonNull Fragment[] fragments) {
        return initMultiFragments(showIndex, fragments, new String[fragments.length]);
    }

    /**
     * 初始化多个fragment
     * @param showIndex 初始显示fragment的索引
     */
    public Fragment[] initMultiFragments(int showIndex, @NonNull Fragment[] fragments, String[] customSuffixTags) {
        FragmentTransaction ft = this.fragmentManager.beginTransaction();
        for (int i = 0; i < fragments.length; i++) {
            Fragment fragment = fragments[i];
            if (!fragment.isAdded()) {
                ft.add(this.fragmentContainerResId, fragment, fragment.getClass().getName() + (customSuffixTags[i] != null ? customSuffixTags[i] : ""));
            }
            ft.hide(fragment).setMaxLifecycle(fragment, Lifecycle.State.STARTED);
        }
        ft.show(fragments[showIndex])
                .setMaxLifecycle(fragments[showIndex], Lifecycle.State.RESUMED)
                .setPrimaryNavigationFragment(fragments[showIndex]);
        ft.commitAllowingStateLoss();
        fragmentManager.executePendingTransactions();
        return fragments;
    }

    /**
     * 多fragment情况下显示指定fragment(fragment类的路径名作为tag)
     */
    public void show(Class<? extends Fragment> fragClass) {
        show(fragClass, null);
    }

    /**
     * 多fragment情况下隐藏指定fragment(fragment类的路径名作为tag)
     */
    public void hide(Class<? extends Fragment> fragClass) {
        hide(fragClass, null);
    }

    /**
     * 多fragment情况下显示指定fragment(fragment类的路径名作为tag)
     */
    public void show(Class<? extends Fragment> fragClass, String customTagSuffix) {
        Fragment fragment;
        if ((fragment = findFragment(fragClass, customTagSuffix)) == null) {
            throw new NullPointerException("show() or hide() fragment前需要先add");
        }

        showHideFragment(true, fragment);
    }

    /**
     * 多fragment情况下隐藏指定fragment(fragment类的路径名作为tag)
     */
    public void hide(Class<? extends Fragment> fragClass, String customTagSuffix) {
        Fragment fragment;
        if ((fragment = findFragment(fragClass, customTagSuffix)) == null) {
            throw new NullPointerException("show() or hide() fragment前需要先add");
        }

        showHideFragment(false, fragment);
    }

    /**
     * 多fragment情况下隐藏指定fragment
     */
    public void hide(@NonNull Fragment fragment) {
        showHideFragment(false, fragment);
    }

    /**
     * 多fragment情况下显示指定fragment
     */
    public void show(@NonNull Fragment fragment) {
        showHideFragment(true, fragment);
    }


    /**
     * 启动新的fragment，跳转后可以返回
     */
    public void start(Fragment fragment) {
        start(fragment, null);
    }

    /**
     * replace fragment 方式，启动新的fragment，跳转后可以返回
     */
    public void replace(Fragment fragment) {
        replace(fragment, null);
    }

    public void start(Fragment fragment, String backStack) {
        startFragment(fragment, false, true, backStack);
    }

    public void replace(Fragment fragment, String backStack) {
        startFragment(fragment, true, true, backStack);
    }

    /**
     * 结束当前fragment，跳转到新的fragment
     */
    public void startWithPop(Fragment fragment) {
        startFragment(fragment, false, false, null);
    }


    /**
     * replace fragment方式，结束当前fragment，跳转到新的fragment
     */
    public void replaceWithPop(Fragment fragment) {
        startFragment(fragment, true, false, null);
    }


    /**
     * fragment出栈，相当于返回
     */
    public void pop() {
        fragmentManager.popBackStack();
    }

    /**
     * fragment出栈
     * @param tag  BackStack对应的tag
     * @param flag 1表示弹出之上的，不包含tag对应的fragment{@link FragmentManager#POP_BACK_STACK_INCLUSIVE}，0表示连同对应tag的fragment一起弹出
     */
    public void pop(String tag, int flag) {
        fragmentManager.popBackStack(tag, flag);
    }

    /**
     * 打印当前fragmentManager下的fragment层次结构
     */
    public String printFragmentStack() {

        StringBuilder sb = new StringBuilder();
        sb.append("当前fragment栈:");
        sb.append("(fragmentManager hash code:");
        sb.append(fragmentManager.hashCode()).append(")\n");
        listFragments(fragmentManager, 1, sb);
        return sb.toString();
    }

    private StringBuilder listFragments(FragmentManager fragmentManager, int hierarchy, StringBuilder stringBuilder) {

        for (Fragment fragment1 : fragmentManager.getFragments()) {

            for (int i = 0; i < hierarchy; i++) {
                stringBuilder.append("--");
            }
            stringBuilder.append(fragment1.getClass().getName());
            stringBuilder.append("@");
            stringBuilder.append(fragment1.hashCode());
            stringBuilder.append("\n");

            stringBuilder = listFragments(fragment1.getChildFragmentManager(), hierarchy + 1, stringBuilder);
        }
        return stringBuilder;
    }

    /**
     * 显示新的fragment
     */
    private void startFragment(Fragment fragment, boolean replace, boolean addToBackstack, String backStack) {
        FragmentTransaction ft = fragmentManager.beginTransaction();
        if (replace) {
            //直接替换
            ft.replace(fragmentContainerResId, fragment, fragment.getClass().getName());
        } else {
            Fragment from = fragmentManager.getPrimaryNavigationFragment();
            //hide当前
            if (from != null) ft.hide(from).setMaxLifecycle(from, Lifecycle.State.STARTED);
            //如果已经added，不做处理
            if (!fragment.isAdded()) ft.add(fragmentContainerResId, fragment, fragment.getClass().getName());

            ft.show(fragment)
                    .setMaxLifecycle(fragment, Lifecycle.State.RESUMED)
                    .setPrimaryNavigationFragment(fragment);
        }

        if (addToBackstack) {
            ft.addToBackStack(backStack);
        }

        ft.commitAllowingStateLoss();
        fragmentManager.executePendingTransactions();
    }

    /**
     * 显示或者隐藏fragment
     */
    private void showHideFragment(boolean isShow, @NonNull Fragment fragment) {
        FragmentTransaction ft = this.fragmentManager.beginTransaction();
        if (isShow) {
            ft.show(fragment)
                    .setMaxLifecycle(fragment, Lifecycle.State.RESUMED)
                    .setPrimaryNavigationFragment(fragment);
        } else {
            ft.hide(fragment).setMaxLifecycle(fragment, Lifecycle.State.STARTED);
        }
        ft.commitAllowingStateLoss();
        this.fragmentManager.executePendingTransactions();
    }
}
